From 9990621f33d08372a02380e632c21173d1ad3c61 Mon Sep 17 00:00:00 2001 From: Tim Deegan Date: Mon, 26 Feb 2007 13:56:01 +0000 Subject: [PATCH] [XEN] Allow log-dirty mode to be enabled on already-shadowed domains. and catch a few missing mark_dirty() calls Signed-off-by: Tim Deegan --- xen/arch/x86/hvm/hvm.c | 2 ++ xen/arch/x86/hvm/io.c | 10 +++++++ xen/arch/x86/mm/shadow/common.c | 45 ++++++++++++-------------------- xen/arch/x86/mm/shadow/multi.c | 34 +++++------------------- xen/arch/x86/mm/shadow/private.h | 3 +-- xen/include/asm-x86/shadow.h | 5 ++-- 6 files changed, 38 insertions(+), 61 deletions(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 0d30ac7a11..326f3c0ed3 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -398,6 +398,8 @@ static int __hvm_copy(void *buf, paddr_t addr, int size, int dir, int virt) memcpy(buf, p, count); /* dir == FALSE: *from guest */ unmap_domain_page(p); + + mark_dirty(current->domain, mfn); addr += count; buf += count; diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c index 677c20c9d5..3a7a875bcc 100644 --- a/xen/arch/x86/hvm/io.c +++ b/xen/arch/x86/hvm/io.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #include @@ -739,6 +741,7 @@ void hvm_io_assist(struct vcpu *v) ioreq_t *p; struct cpu_user_regs *regs; struct hvm_io_op *io_opp; + unsigned long gmfn; io_opp = &v->arch.hvm_vcpu.io_op; regs = &io_opp->io_context; @@ -763,6 +766,13 @@ void hvm_io_assist(struct vcpu *v) /* Copy register changes back into current guest state. */ hvm_load_cpu_guest_regs(v, regs); memcpy(guest_cpu_user_regs(), regs, HVM_CONTEXT_STACK_BYTES); + + /* Has memory been dirtied? */ + if ( p->dir == IOREQ_READ && p->data_is_ptr ) + { + gmfn = get_mfn_from_gpfn(paging_gva_to_gfn(v, p->data)); + mark_dirty(v->domain, gmfn); + } } /* diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index e3b4821010..93233c83fc 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -981,7 +981,6 @@ mfn_t shadow_alloc(struct domain *d, INIT_LIST_HEAD(&sp[i].list); sp[i].type = shadow_type; sp[i].pinned = 0; - sp[i].logdirty = 0; sp[i].count = 0; sp[i].backpointer = backpointer; sp[i].next_shadow = NULL; @@ -1230,7 +1229,6 @@ static unsigned int sh_set_allocation(struct domain *d, { sp[j].type = 0; sp[j].pinned = 0; - sp[j].logdirty = 0; sp[j].count = 0; sp[j].mbz = 0; sp[j].tlbflush_timestamp = 0; /* Not in any TLB */ @@ -2558,7 +2556,7 @@ static int shadow_one_bit_enable(struct domain *d, u32 mode) ASSERT(shadow_locked_by_me(d)); /* Sanity check the call */ - if ( d == current->domain || (d->arch.paging.mode & mode) ) + if ( d == current->domain || (d->arch.paging.mode & mode) == mode ) { return -EINVAL; } @@ -2589,7 +2587,7 @@ static int shadow_one_bit_disable(struct domain *d, u32 mode) ASSERT(shadow_locked_by_me(d)); /* Sanity check the call */ - if ( d == current->domain || !(d->arch.paging.mode & mode) ) + if ( d == current->domain || !((d->arch.paging.mode & mode) == mode) ) { return -EINVAL; } @@ -2646,17 +2644,7 @@ static int shadow_test_enable(struct domain *d) domain_pause(d); shadow_lock(d); - - if ( shadow_mode_enabled(d) ) - { - SHADOW_ERROR("Don't support enabling test mode" - " on already shadowed doms\n"); - ret = -EINVAL; - goto out; - } - ret = shadow_one_bit_enable(d, PG_SH_enable); - out: shadow_unlock(d); domain_unpause(d); @@ -2722,10 +2710,10 @@ static int shadow_log_dirty_enable(struct domain *d) if ( shadow_mode_enabled(d) ) { - SHADOW_ERROR("Don't (yet) support enabling log-dirty" - " on already shadowed doms\n"); - ret = -EINVAL; - goto out; + /* This domain already has some shadows: need to clear them out + * of the way to make sure that all references to guest memory are + * properly write-protected */ + shadow_blow_tables(d); } #if (SHADOW_OPTIMIZATIONS & SHOPT_LINUX_L3_TOPLEVEL) @@ -2917,12 +2905,18 @@ static int shadow_log_dirty_op( void sh_mark_dirty(struct domain *d, mfn_t gmfn) { unsigned long pfn; - - ASSERT(shadow_locked_by_me(d)); + int do_locking; if ( !shadow_mode_log_dirty(d) || !mfn_valid(gmfn) ) return; + /* Although this is an externally visible function, we do not know + * whether the shadow lock will be held when it is called (since it + * can be called from __hvm_copy during emulation). + * If the lock isn't held, take it for the duration of the call. */ + do_locking = !shadow_locked_by_me(d); + if ( do_locking ) shadow_lock(d); + ASSERT(d->arch.paging.shadow.dirty_bitmap != NULL); /* We /really/ mean PFN here, even for non-translated guests. */ @@ -2962,13 +2956,8 @@ void sh_mark_dirty(struct domain *d, mfn_t gmfn) mfn_to_page(gmfn)->count_info, mfn_to_page(gmfn)->u.inuse.type_info); } -} -void shadow_mark_dirty(struct domain *d, mfn_t gmfn) -{ - shadow_lock(d); - sh_mark_dirty(d, gmfn); - shadow_unlock(d); + if ( do_locking ) shadow_unlock(d); } /**************************************************************************/ @@ -2992,9 +2981,7 @@ int shadow_domctl(struct domain *d, if ( shadow_mode_log_dirty(d) ) if ( (rc = shadow_log_dirty_disable(d)) != 0 ) return rc; - if ( is_hvm_domain(d) ) - return -EINVAL; - if ( d->arch.paging.mode & PG_SH_enable ) + if ( d->arch.paging.mode == PG_SH_enable ) if ( (rc = shadow_test_disable(d)) != 0 ) return rc; return 0; diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c index 837e34733c..e96972a9d5 100644 --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -101,14 +101,6 @@ get_fl1_shadow_status(struct vcpu *v, gfn_t gfn) /* Look for FL1 shadows in the hash table */ { mfn_t smfn = shadow_hash_lookup(v, gfn_x(gfn), SH_type_fl1_shadow); - - if ( unlikely(shadow_mode_log_dirty(v->domain) && mfn_valid(smfn)) ) - { - struct shadow_page_info *sp = mfn_to_shadow_page(smfn); - if ( !(sp->logdirty) ) - shadow_convert_to_log_dirty(v, smfn); - } - return smfn; } @@ -118,14 +110,6 @@ get_shadow_status(struct vcpu *v, mfn_t gmfn, u32 shadow_type) { mfn_t smfn = shadow_hash_lookup(v, mfn_x(gmfn), shadow_type); perfc_incrc(shadow_get_shadow_status); - - if ( unlikely(shadow_mode_log_dirty(v->domain) && mfn_valid(smfn)) ) - { - struct shadow_page_info *sp = mfn_to_shadow_page(smfn); - if ( !(sp->logdirty) ) - shadow_convert_to_log_dirty(v, smfn); - } - return smfn; } @@ -136,12 +120,6 @@ set_fl1_shadow_status(struct vcpu *v, gfn_t gfn, mfn_t smfn) SHADOW_PRINTK("gfn=%"SH_PRI_gfn", type=%08x, smfn=%05lx\n", gfn_x(gfn), SH_type_fl1_shadow, mfn_x(smfn)); - if ( unlikely(shadow_mode_log_dirty(v->domain)) ) - // mark this shadow as a log dirty shadow... - mfn_to_shadow_page(smfn)->logdirty = 1; - else - mfn_to_shadow_page(smfn)->logdirty = 0; - shadow_hash_insert(v, gfn_x(gfn), SH_type_fl1_shadow, smfn); } @@ -156,12 +134,6 @@ set_shadow_status(struct vcpu *v, mfn_t gmfn, u32 shadow_type, mfn_t smfn) d->domain_id, v->vcpu_id, mfn_x(gmfn), shadow_type, mfn_x(smfn)); - if ( unlikely(shadow_mode_log_dirty(d)) ) - // mark this shadow as a log dirty shadow... - mfn_to_shadow_page(smfn)->logdirty = 1; - else - mfn_to_shadow_page(smfn)->logdirty = 0; - #ifdef CONFIG_COMPAT if ( !IS_COMPAT(d) || shadow_type != SH_type_l4_64_shadow ) #endif @@ -3994,6 +3966,8 @@ sh_x86_emulate_write(struct vcpu *v, unsigned long vaddr, void *src, /* If we are writing zeros to this page, might want to unshadow */ if ( likely(bytes >= 4) && (*(u32 *)addr == 0) && is_lo_pte(vaddr) ) check_for_early_unshadow(v, mfn); + + sh_mark_dirty(v->domain, mfn); sh_unmap_domain_page(addr); shadow_audit_tables(v); @@ -4047,6 +4021,8 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, unsigned long vaddr, if ( likely(bytes >= 4) && (*(u32 *)addr == 0) && is_lo_pte(vaddr) ) check_for_early_unshadow(v, mfn); + sh_mark_dirty(v->domain, mfn); + sh_unmap_domain_page(addr); shadow_audit_tables(v); return rv; @@ -4087,6 +4063,8 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v, unsigned long vaddr, if ( *(u32 *)addr == 0 ) check_for_early_unshadow(v, mfn); + sh_mark_dirty(v->domain, mfn); + sh_unmap_domain_page(addr); shadow_audit_tables(v); return rv; diff --git a/xen/arch/x86/mm/shadow/private.h b/xen/arch/x86/mm/shadow/private.h index 322871acb6..479ed26959 100644 --- a/xen/arch/x86/mm/shadow/private.h +++ b/xen/arch/x86/mm/shadow/private.h @@ -229,8 +229,7 @@ struct shadow_page_info struct { unsigned int type:4; /* What kind of shadow is this? */ unsigned int pinned:1; /* Is the shadow pinned? */ - unsigned int logdirty:1; /* Was it made in log-dirty mode? */ - unsigned int count:26; /* Reference count */ + unsigned int count:27; /* Reference count */ u32 mbz; /* Must be zero: this is where the owner * field lives in a non-shadow page */ } __attribute__((packed)); diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h index 5a3dbfc72e..cfd8e841c8 100644 --- a/xen/include/asm-x86/shadow.h +++ b/xen/include/asm-x86/shadow.h @@ -87,12 +87,13 @@ void shadow_final_teardown(struct domain *d); /* Mark a page as dirty in the log-dirty bitmap: called when Xen * makes changes to guest memory on its behalf. */ -void shadow_mark_dirty(struct domain *d, mfn_t gmfn); +void sh_mark_dirty(struct domain *d, mfn_t gmfn); /* Cleaner version so we don't pepper shadow_mode tests all over the place */ static inline void mark_dirty(struct domain *d, unsigned long gmfn) { if ( unlikely(shadow_mode_log_dirty(d)) ) - shadow_mark_dirty(d, _mfn(gmfn)); + /* See the comment about locking in sh_mark_dirty */ + sh_mark_dirty(d, _mfn(gmfn)); } /* Update all the things that are derived from the guest's CR0/CR3/CR4. -- 2.30.2